
import java.io.*;
import java.net.*;
import java.lang.Integer;

/* class Client
   This is the class having the main method.
   There are many functions implemented, all of which I have not used in this project, because of the scope of project.
   I have tried to give meaning full names to the method names, each of the names imply exactly what functionlity they perform.
   

*/
public class Client{
	
  	String SERVER_HOST = new String("localhost");
	int SERVER_PORT = 0;
	InetAddress serverInetAddress;
	Socket serverSocketAddress;
	BufferedReader mySocketReader,myInputReader;
	PrintWriter mySocketWriter;
	
	
	
  public Client() throws Exception
  {     //Initialises all the varibales that would be required...
	    
		System.out.println("Please enter Server port # : ");
		myInputReader = new BufferedReader( new InputStreamReader (System.in));
		SERVER_PORT = Integer.parseInt( new String( myInputReader.readLine() ));
	    //SERVER_PORT = 15687;
	    serverInetAddress = InetAddress.getByName(SERVER_HOST);
	    serverSocketAddress = new Socket( serverInetAddress , SERVER_PORT);
	    mySocketReader = new BufferedReader(new InputStreamReader( serverSocketAddress.getInputStream()));
	    mySocketWriter = new PrintWriter(new OutputStreamWriter( serverSocketAddress.getOutputStream()));
	
  }// End constructor Client()

// Used to clear screen when there is a lot of data on the screen
  static public void clearScreen()
  {
	int i = 0;
	for(i=0;i<100;i++)
	{
		System.out.println("\n");
	}
	
  }// End clearScreen

// This is the functino which sends out connection request to the server.
  public void establishConnection() throws Exception
  {
	mySocketWriter.println("Connection Request");
	mySocketWriter.flush();
	
  }// End establishConnection

// this funciton returns if the connection was accepted, as the server is configured to handel only 5 connections at the same time. 
// If it exceeds the number all the others would be queued.

  public boolean getConnectionConfirmation() throws Exception
  {
	String confirmation = new String(mySocketReader.readLine());
	System.out.println("Connection :: " + confirmation); 
	if(confirmation.equalsIgnoreCase("QUEUED"))
	 {
		 return false;
     }
	
	return true;
  }// End getConnectionConfirmation()

// this mehod helps user login into the Server, it asks for user login information.
  public void login() throws Exception
  {
     // Sends "Login Name to Server"
        String loginName;
        System.out.println("Please Enter - Login Name : ");
        loginName = new String( myInputReader.readLine());
     	mySocketWriter.println(loginName);
	    mySocketWriter.flush();
     	
  }// End Llogin()

// this method gets all the services that the server has to offer.
  public void getServerServices() throws Exception
  { // Reading menu
	boolean lastLine = false;
	String services = new String("");
	while( !lastLine )
	{ 
	  services = mySocketReader.readLine();
	  lastLine = services.equalsIgnoreCase("flagLastLine");
	  if (!lastLine)
	  {
		System.out.println(services);
	  }
    }
  }// End getServerServices()


// Requests for services from the server
  public int requestService() throws Exception
  {
	//Sends service Number
	//System.out.println("Inside requestService\n");
	int serviceNumber = 0;
	serviceNumber = Integer.parseInt(new String(myInputReader.readLine()));
	//System.out.println("Client reuqested : " + serviceNumber );
	mySocketWriter.println(serviceNumber);
	mySocketWriter.flush();
	return serviceNumber;
	
  }// End requestService()  

// Waits for the response from the server, if the server is too busy.
  public void waitForServer() throws Exception
  {
	System.out.println(new String(mySocketReader.readLine()));

  }// End waitForServer()


// This method actually handels all communication from the server. All 6 services have been handeled by this function.
  public void receiveService(int serviceNumber) throws Exception
  {
		int service = serviceNumber;
		String accountName = new String();
		//System.out.println("Service Case Number" + service);
		switch(service)
		{
		    case 1:{  // Login Service
			         System.out.println("Client Connected");
			         break;
		           }
		  
		    case 2:{ 	// Login
				        
				        System.out.println("Enter login name :: "); 
				        mySocketWriter.println(new String(myInputReader.readLine()));
				        mySocketWriter.flush();
				        System.out.println("You have successfully Logged in ..!! \n");
					    break;	
		           }
		 
		    case 3:{ 
			             // Creating an Account
                         System.out.println("Enter Account Name");
				         String serverText = new String(mySocketReader.readLine());
				         System.out.println(serverText);
				         accountName = myInputReader.readLine();
				         mySocketWriter.println(accountName);
				         mySocketWriter.flush();
				         System.out.println("Account Successfully Created on Server !!!");
				         break;
		           }
		
		    case 4:{ 	// List of Valid Accounts
				         System.out.println("service ::List Valid Accounts ..");
                         String validAccounts = new String(mySocketReader.readLine());
                         while (!validAccounts.equalsIgnoreCase("endingFlag"))
                         {                           
	                       System.out.println(validAccounts);
	                       validAccounts = new String(mySocketReader.readLine());
	                     }
                         System.out.println("\n");                               
				         break;
		           }
		
		    case 5:{  	// List of Current Online Users
				         System.out.println("service ::List LoggedIn Users ..");
				         String loggedInUsers = new String(mySocketReader.readLine());
				         while(!loggedInUsers.equalsIgnoreCase("endingFlag"))
				         {
					       System.out.println(loggedInUsers);
					       loggedInUsers = new String(mySocketReader.readLine());
				         }
                         System.out.println("\n");
				         break;
		           }
		   
		    case 6:{  	// Join group Chat Room
				         System.out.println("service ::Join Group Chat");
				         String defaultGroups = new String(mySocketReader.readLine());
				         while(!defaultGroups.equalsIgnoreCase("endingFlag"))
				         {
				            System.out.println(defaultGroups);
				            defaultGroups = new String(mySocketReader.readLine());
				          }
				          //System.out.println("\n");
				        				        				         
				          mySocketWriter.println(myInputReader.readLine());
				          mySocketWriter.flush();
				         //System.out.println("Waiting for Socket Address from Server.");
				        // Read the new socket communicated by the server and then connect that socket 
				        int groupPortNumber = Integer.parseInt(new String(mySocketReader.readLine()));
				        //System.out.println("Port Number received as : "+ groupPortNumber);
				        Socket groupChatSocket = new Socket(InetAddress.getByName("localhost"),groupPortNumber);
				        //System.out.println("Group Chat Socket Number  "+ groupChatSocket);
				        BufferedReader myGroupChatSocketReader = new BufferedReader(new InputStreamReader(groupChatSocket.getInputStream()));
				        PrintWriter myGroupChatSocketWriter = new PrintWriter(new OutputStreamWriter(groupChatSocket.getOutputStream()));
				        
				        // Now we have handels to communicate with the server, just keep sending messages untill user wants to stop
				       boolean chatSession = true;
				       System.out.println("Group Chat session has started, have fun.....!!!");
				       while(chatSession)
				       {
					       BufferedReader groupInputReader = new BufferedReader(new InputStreamReader(System.in));
					       
					       String text = groupInputReader.readLine();
					      
					       if(!(text.equalsIgnoreCase("quit")|| text.equalsIgnoreCase("q")||text.equalsIgnoreCase("QUIT")))
					       {
					         myGroupChatSocketWriter.println(text);
					         myGroupChatSocketWriter.flush();     
					
					       }else{chatSession = false;}
					       
				       }
				
				         break;
		           }
		
			
		    case 7:{ 
				         System.out.println("You have logged out successfully...\n");
				         break;
			       }

	    	default: { // Add some more mechanism to call this function again, so that a correct service can be selected.
					       System.out.println("Invalid Selection :");
				           break;
			         }
			
			
		}// End switch()
	
	
  }// End receiveService()

  public boolean needsMoreService() throws Exception
  {
	System.out.println("Request service from Server ? y/yes/Y/YES/n/no/N/NO");
	String response = new String(myInputReader.readLine());
	//System.out.println(response);
	
	if(response.equalsIgnoreCase("yes")||response.equalsIgnoreCase("y")||response.equalsIgnoreCase("Y")||response.equalsIgnoreCase("YES"))
	  return true;
	else if(response.equalsIgnoreCase("no")||response.equalsIgnoreCase("n")||response.equalsIgnoreCase("N")||response.equalsIgnoreCase("NO"))
	  return false;
	else System.out.println("I guess you did not enter correct option..\n I assume you are tired..\n Exiting ..\n");
	  return false;
	
  }// End needsMoreServices

  public void closeAllConnections() throws Exception
  {
	serverSocketAddress.close();
	
  }// End closeAllConnections()

  

  public static void main(String[] args)
 {
   try{
	  
	  Client myClient = new Client();
	  myClient.establishConnection();
	  if(myClient.getConnectionConfirmation())
	  {	
	    myClient.login();
	
	    boolean clientRequesting = true;
	    while( clientRequesting )
	    {
		  //clearScreen();  Keeps getting the services that the client needs from the server untill the service number is 7, which is the end of communicaiton.
		  if(myClient.needsMoreService())
		  {
	        myClient.getServerServices();
	        int serviceNumber = myClient.requestService();
	        if(serviceNumber !=7 )
	        {
	          myClient.receiveService(serviceNumber);
	        }else{clientRequesting = false;}
	      }else{clientRequesting = false;}
	    }
	
	    
      }else{ // This happends when the server is over loaded, the client keeps waiting untill interupted by the server
	    myClient.waitForServer();
	    myClient.login();
	    myClient.getServerServices();
	    myClient.requestService();
	
      }
 

      System.out.println("Closing all connections to Server..");
      myClient.closeAllConnections();

	 }catch(ConnectException e){ System.out.println("Could not connect to Server..\nTry starting the Server First - Thank you !!");}
	   catch(Exception e){System.out.println(e);}


  }

}